#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <iostream>
using namespace std;
#include <string>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
const int basesize = 1024;
#include <string>
//#define nullptr 0

//string User()
//{
//  char* user = getenv("USER");
//  string name(user);
//  // char* user =(char*) malloc(basesize);
// // strncpy(user,tmp,basesize);
// // return user;
//  return name;
//}
//
//string HostName()
//{
//  char*hostName = getenv("HOSTNAME");
//  string ret(hostName);
//  return ret;
//  //  if(tmp==nullptr)
////    return nullptr;
////  char* hostName = (char*)malloc(basesize);
////  strncpy(hostName,tmp,basesize);
//  //.autorelabelturn hostName;
//}
//    
//string Pwd()
//{
//	char* pwd = getenv("PWD");
//  string ret(pwd);
////  char* pwd = (char*)malloc(basesize);
////  strncpy(pwd,tmp,basesize);
//	//return pwd;
//  return ret;
//
//}
//#define SIZE 64;
const int envnum = 64;
char* genv[envnum];
const int size = 64;
char command_line[size];
int gargc;
char* gargv[64];
char pwd[basesize];
char pwdenv[basesize];

int redir = 0;
#define NonR        0
#define InputRedir  1
#define OutputRedir 2
#define AppendRedir 3
char* filename = nullptr;
string GetUser()
{
  char* user = getenv("USER");
  
  if(user==nullptr)
    return "None";
  string ret(user);
  //srvtring name(user);
  return ret;
}
string GetHostName()
{
  char* hostname = getenv("HOSTNAME");
  if(hostname==nullptr)
    return "None";
  string ret(hostname);
  //srvtring ret(hostname);
  return ret;
}
string PWD()
{
  if(nullptr==getcwd(pwd,sizeof(pwd)))  
    return "None";
  snprintf(pwdenv,basesize,"PWD=%s",pwd);
  putenv(pwdenv);
  return pwd;
  //char* pwd = getenv("PWD");
  //if(pwd==nullptr)
  //  return "None";
  //string ret(pwd);
  ////srvtring ret(pwd);
  //return ret;
}
void PrintMessage()
{

  // [wmz@hcss-ecs-14db myshell]$
  char str[basesize];
 //.autorelabel char* user = getenv("USER");
  string path = PWD();
  if(path=="/"||path=="None")
  {
    //do nothing
  }
  size_t pos = path.rfind("/");
  if(pos==std::string::npos)
  {
    //do nothing;
  }
  else
  {
    path = path.substr(pos+1);
  }
  snprintf(str,basesize,"[%s@%s %s]#",GetUser().c_str(),GetHostName().c_str(),path.c_str());
  //string name(user);
  //varsnprintf(str,basesize,"[%s@]",name.c_str());
  //CloudrResetPwdAgentsnprintf(str,basesize,"[%s@%s %s]#",getenv("USER"),getenv("HOSTNAME"),getenv("PWD"));
  printf("%s",str);
  fflush(stdout);
}


void GetCommandLine()
{
  char* result = fgets(command_line,basesize,stdin);
  if(!result)
  {
    printf("Get Command Error\n");
    return;
  }
  int len = strlen(result);
  result[len-1] = '\0';

}




#define TruncSpace(x) do{\
  while(command_line[end]==' ')\
  { x++; };\
}while(0); 

void PraseCommandLine(char* command_line,int len)
{
  memset(gargv,0,sizeof(char*)*gargc);
  gargc = 0;
  redir = 0;
  filename = nullptr;
  int end = strlen(command_line);
  end--;
  while(end>=0)
  {
    if(command_line[end]=='<')
    {
      redir = InputRedir;
      command_line[end] = 0;
      end++;
      TruncSpace(end);
      filename = command_line+end;
      break;
    }
    else if(command_line[end]=='>')
    {
      redir = OutputRedir;
      command_line[end] = 0;
      if(end-1>=0&&command_line[end-1]=='>')
      {
        command_line[end-1] = 0;
        redir = AppendRedir;
       // command_line[end]= 0;
      }
      end++;
      TruncSpace(end);
      filename = command_line+end;
      break;
    }
    else
    {
      end--;
    }
  }
  //cout<<filename<<endl;
//  if(filename)
//   printf("%s\n",filename);
//  else 
//    printf("NonFilename\n");
  const char* sep = " ";
  //gargv[gargc++] = command_line;
  if(len==0)
  {
    gargv[gargc] = nullptr;
    return;
  }
  gargv[gargc++] = strtok(command_line,sep);
//  if(len==0)
//  {
//    gargv[gargc] = nullptr;
//    return;
//  }
//  else
//  {
//    gargv[gargc++] = command_line;
//  
//  }
//  if(!next)
//  {
//:    gargv[gargc] = nullptr;
//    return;
//  }
//  else
//  {
//    *next = '\0';
//    gargv[gargc++] = next+1;
//  }
    //  if(!next)
//  {
//    gargv[gargc++] = nullptr;
//    return;
//  }
//  else
//  {
//    *next = '\0';
//    gargv[gargc++] = next+1;
//  }
  while((bool)(gargv[gargc++] = strtok(nullptr,sep)))
  {
    ;
  }
  gargc--;
}

void Print()
{
  printf("gargc:%d\n",gargc);
  for(int i = 0;gargv[i];i++)
  {
    printf("gargv[%d]:%s\n",i,gargv[i]);
  }
}

bool ExecCommandLine()
{
  extern char** environ;
  pid_t pid = fork();
  //失败
  if(pid<0)
  {
    cout<<"创建子进程失败"<<endl;
    return false;
  }
  else if(pid==0)
  {
    if(redir==InputRedir)
    {
      if(!filename) 
      {
        //do nothing
      }
      else
      {
        int fd = open(filename,O_RDONLY);
        dup2(fd,0);

      }
    }
    else if(redir==OutputRedir)
    {
      if(!filename)
      {
        //do nothing
      }
      else
      {
        int fd = open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);
        dup2(fd,1);
      }
    }
    else if(redir==AppendRedir)
    {
      if(!filename)
      {
        //do nothing
      }
      else
      {
        int fd = open(filename,O_WRONLY|O_CREAT|O_APPEND,0666);
        dup2(fd,1);
      }  

    }
    execvpe(gargv[0],gargv,environ);
    exit(0);
  }

  int status = 0;
  pid_t rid = waitpid(pid,&status,0);
  if(rid>0)
      return true;
  return false;


}
void printenv()
{
  extern char** environ;
  for(int i = 0;environ[i];i++)
  {
    cout<<environ[i]<<endl;
  }
  cout<<endl<<endl;
  for(int i= 0;genv[i];i++)
  {
    cout<<genv[i]<<endl;

  }

}
void LoadEnv()
{
  extern char** environ;
  int i;
  for(i = 0;environ[i];i++)
  {
  
    
    genv[i] = (char*)malloc(strlen(environ[i])+1);
    strncpy(genv[i],environ[i],strlen(environ[i]));
    genv[i][strlen(environ[i])] = '\0';
  }
  genv[i] = nullptr;
  //printenv();
}

void AddEnv(char* env,int len)
{
  int index = 0;
  while(genv[index])
  {
    index++;
  }
  genv[index] =(char*)malloc(len+1);
 // genv[index][len] = '\0';
  strncpy(genv[index++],env,len+1);
  genv[index] = nullptr;
}



int lastcode = 0;
bool CheckCommandBuiltAndExec()
{
  if(strcmp(gargv[0],"cd")==0)
  {
    if(gargc==2)
    {
      chdir(gargv[1]);
      lastcode = 0;
      return true;
    }
    else
    {
      lastcode = 1;
    }
  }
  else if(strcmp(gargv[0],"env")==0)
  {
    for(int i = 0;genv[i];i++)
    {
      printf("%s\n",genv[i]);
      
    }
    lastcode = 0;
    return true;
  }
  else if(strcmp(gargv[0],"export")==0)
  {
    if(gargc==2)
    {
      AddEnv(gargv[1],strlen(gargv[1]));
      lastcode = 0;
      return true;
    }
    else
    {
      lastcode = 2;
    }
  
  }
  else if(strcmp(gargv[0],"echo")==0)
  {
    if(gargc==2)
    {
      if(gargv[1][0]=='$')
      {
        if(gargv[1][1]=='?')
         printf("%d",lastcode);
        lastcode = 0;
      }
      else
      {
        printf("%s",gargv[1]);
        lastcode = 0;
      }
    }
    else
    {
      lastcode = 3;
    }
  }
  return false;
}
int main()
{
  LoadEnv();
  while(true)
  {
    PrintMessage();
  //  printf("hello world\n");
    //sleep(200);
    GetCommandLine();
    PraseCommandLine(command_line,strlen(command_line));
    if(CheckCommandBuiltAndExec())
    {
      continue;
    }
    ExecCommandLine();
    //Print();
  }
  return 0;
}
